#define LG_CORE

#include <memory.h>

#include "lg_ref.h"

static struct {
	LGRef gc;
	LGRef* gcEnd;
}ctx = { 0 };

extern int
lgInitRefContext(LGConfig* config) {
	ctx.gcEnd = &ctx.gc;
	return 0;
}

extern void
lgAutoGcRef() {
	LGRef* next = ctx.gc.gcNext;
	LGRef* temp;
	while (next) {
		temp = next->gcNext;
		lgReleaseRef(next);
		next = temp;
	}
	ctx.gc.gcNext = NULL;
}

LG_API void*
lgNewRef(size_t size, LGRefFree free) {
	LGRef* ref = malloc(size);
	memset(ref, 0, size);
	ref->ref = 1;
	ref->free = free;
	ref->gcNext = NULL;
	(*ctx.gcEnd).gcNext = ref;
	ctx.gcEnd = ref;
	return ref;
}

LG_API void
lgFreeRef(void* p) {
	LGRef* ref = (LGRef*)p;
	if (ref->ref <= 0) {
		return;
	}
	ref->ref = 0;
	if (ref->free) {
		ref->free(ref);
	}
	free(ref);
}

LG_API void
lgRetainRef(void* ref) {
	((LGRef*)ref)->ref++;
}

LG_API void
lgReleaseRef(void* p) {
	LGRef* ref = (LGRef*)p;
	ref->ref--;
	if (ref->ref > 0) {
		return;
	}
	if (ref->free) {
		ref->free(ref);
	}
	free(ref);
}

LG_API unsigned
lgCountRef(void* ref) {
	return ((LGRef*)ref)->ref;
}
